package dnet

import (
	"dgo/goutils/utils"
	"fmt"
	"net"
	"os"
	"sync/atomic"
	"time"
)

// 连接对象
type TcpServerClientConnectionV0 struct {
	handle            uint32
	conn              net.Conn
	owner             *TcpServerV0
	sendTaskStartFlag int32
	sendTask          *utils.QueueTask
	remoteAddr        string

	closeFlag int32
	recvbytes int64
	sendbytes int64

	connecttime  time.Time
	distime      time.Time
	lastsendtime time.Time
	lastrecvtime time.Time
	TagPtr       interface{}

	SendMonitor *utils.MonitorSpeedSizeRec
	RecvMonitor *utils.MonitorSpeedSizeRec
	LastWarning string

	disReason  string
	OnDisEvent func(sender *TcpServerClientConnectionV0)
}

func NewCommTcpSvrV0ClientConnection(conn net.Conn, tcpSvr *TcpServerV0) *TcpServerClientConnectionV0 {
	rval := &TcpServerClientConnectionV0{
		handle:      utils.NewObjectDNA(),
		conn:        conn,
		owner:       tcpSvr,
		SendMonitor: utils.NewMonitorSpeedSizeRec(),
		RecvMonitor: utils.NewMonitorSpeedSizeRec(),
	}
	if conn != nil {
		rval.remoteAddr = conn.RemoteAddr().String()
	}
	if tcpSvr.MonitorFlag >= 1 {
		utils.Monitor.AddMonitorRec(fmt.Sprintf("%s_%d_recv", tcpSvr.id, rval.handle), rval.RecvMonitor)
		utils.Monitor.AddMonitorRec(fmt.Sprintf("%s_%d_send", tcpSvr.id, rval.handle), rval.SendMonitor)
	}
	return rval
}

func (this *TcpServerClientConnectionV0) Start() {
	if this.owner.UseQueueSend {
		this.checkStartTask()
	}
	this.handleRecv()
}

func (this *TcpServerClientConnectionV0) GetHandle() uint32 {
	return this.handle
}

func (this *TcpServerClientConnectionV0) GetRemoteAddr() string {
	return this.remoteAddr
}

func (this *TcpServerClientConnectionV0) Status() string {
	var sb utils.BytesBuilder
	if this.distime.IsZero() {
		sb.Appendf("状态:在线, 连接时长:%s", utils.DurationStr(time.Now().Sub(this.connecttime)))
	} else {
		sb.Appendf("状态:离线(%s), 连接时长:%s", this.disReason, utils.DurationStr(this.distime.Sub(this.connecttime)))
	}
	sb.AppendStr(",")
	sb.Appendf("sendbytes:%s, recvbytes:%s", utils.HumanFilesize(this.sendbytes), utils.HumanFilesize(this.recvbytes))
	return sb.String()
}

func (this *TcpServerClientConnectionV0) onSendQueueWork(args ...interface{}) {
	buf := args[0].([]byte)
	pop_t := time.Now()
	n, err := this.DirectlySendBuffer(buf)
	if len(args) > 1 {
		if fn, ok := args[1].(func(n int, err error)); ok {
			fn(n, err)
		} else if fn, ok := args[1].(func(n int, pop_t time.Time, err error)); ok {
			fn(n, pop_t, err)
		}
	}
}

func (this *TcpServerClientConnectionV0) GetTimeOut() time.Duration {
	return time.Now().Sub(this.GetLastActivityT())
}

func (this *TcpServerClientConnectionV0) GetConnectedTime() time.Time {
	return this.connecttime
}

func (this *TcpServerClientConnectionV0) GetLastActivityT() time.Time {
	rval := this.connecttime
	if rval.IsZero() || (!this.lastrecvtime.IsZero() && rval.Before(this.lastrecvtime)) {
		rval = this.lastrecvtime
	}

	if rval.IsZero() || (!this.lastsendtime.IsZero() && rval.Before(this.lastsendtime)) {
		rval = this.lastsendtime
	}

	return rval
}

func (this *TcpServerClientConnectionV0) checkKickOut(isec int) {
	lastT := this.GetLastActivityT()
	if lastT.IsZero() {
		this.RequestDisconnect(fmt.Sprintf("%s 未进行任何数据交互,请求断开连接", this.remoteAddr))
		return
	}

	t := time.Since(lastT)
	tick := int(t.Seconds())
	if tick <= isec {
		return
	}
	this.RequestDisconnect(fmt.Sprintf("%s 超时%d秒，未进行数据交互,请求断开连接", this.remoteAddr, tick))
}

func (this *TcpServerClientConnectionV0) GetDisReason() string {
	return this.disReason
}

/*
*

	由接收纤程调用
*/
func (this *TcpServerClientConnectionV0) doClose() {
	if this.sendTask != nil {
		utils.GoFunc2(this.sendTask.Stop)
	}
	this.owner.removeOnline(this)
	utils.Monitor.RemoveMonitorRec(fmt.Sprintf("%s_%d_recv", this.owner.id, this.handle))
	utils.Monitor.RemoveMonitorRec(fmt.Sprintf("%s_%d_send", this.owner.id, this.handle))
}

func (this *TcpServerClientConnectionV0) RequestDisconnect(disReason string) {
	if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) {
		this.disReason = disReason
	}
	this.conn.Close()
}

func (this *TcpServerClientConnectionV0) DirectlySendBuffer(buf []byte) (int, error) {
	if this.closeFlag == 1 { // 已经关闭
		return 0, fmt.Errorf("连接已经关闭")
	}

	this.owner.incSendCnt0()
	defer this.owner.incSendCnt1()

	n, err := this.conn.Write(buf)
	if err != nil {
		this.RequestDisconnect(fmt.Sprintf("[%s]处理发送数据时出现了异常:%v", this.remoteAddr, err))
	} else {
		if this.owner.MonitorFlag >= 1 {
			this.SendMonitor.Delta(int64(n))
		}
		this.lastsendtime = time.Now()
		this.sendbytes = this.sendbytes + int64(n)
	}
	return n, err
}

func (this *TcpServerClientConnectionV0) checkStartTask() {
	if this.sendTask == nil {
		if atomic.CompareAndSwapInt32(&this.sendTaskStartFlag, 0, 1) {
			tmp := utils.NewQueueTask(this.onSendQueueWork)
			tmp.ConfigIdleSleepTime(time.Millisecond)
			tmp.Start()
			this.sendTask = tmp
		} else {
			fmt.Fprintf(os.Stderr, "send err, send task is not ready!")
		}
	}
}

/*
**

	根据owner的UseQueueSend设定进行投递或者直接发送
*/
func (this *TcpServerClientConnectionV0) Send(buf []byte) error {
	sendBuf := buf
	if this.owner.UseQueueSend {
		return this.PostSendBuffer(buf)
	} else {
		_, err := this.DirectlySendBuffer(sendBuf)
		return err
	}
}

func (this *TcpServerClientConnectionV0) PostSendBufferFunc(buffer []byte, onSent func(n int, err error)) error {
	this.checkStartTask()
	if onSent != nil {
		return this.sendTask.Push(buffer, onSent)
	} else {
		return this.sendTask.Push(buffer)
	}
}

func (this *TcpServerClientConnectionV0) PostSendBuffer(buffer []byte) error {
	this.checkStartTask()
	err := this.sendTask.Push(buffer)
	if err != nil {
		this.LastWarning = fmt.Sprintf("[%s]投递发送异常:%s", utils.NowString(), err.Error())
	}
	return err
}

func (this *TcpServerClientConnectionV0) PostSendBufferFunc2(buffer []byte, onSent func(n int, pop_t time.Time, err error)) error {
	this.checkStartTask()
	if onSent != nil {
		return this.sendTask.Push(buffer, onSent)
	} else {
		return this.sendTask.Push(buffer)
	}
}

// 处理连接
func (this *TcpServerClientConnectionV0) handleRecv() {
	if utils.GoFunCatchException {
		defer utils.PanicHandler()
	}
	defer this.doClose()
	for {
		// 避免异步修改
		buffer := make([]byte, this.owner.BlockRecvSize)
		n, err := this.conn.Read(buffer)
		if err != nil {
			this.RequestDisconnect(fmt.Sprintf("%s 处理接受请求时出现了异常: %v", this.conn.RemoteAddr().String(), err))
			break
		}
		if this.owner.MonitorFlag >= 1 {
			this.RecvMonitor.Delta(int64(n))
		}

		this.lastrecvtime = time.Now()
		this.owner.onRecvBuffer(this, buffer[:n])
	}
}
